﻿using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Data.Objects;
using System.Transactions;

namespace FrameworkLib.Facades.Paging
{
    public abstract class PagedFacadeBase<Context> where Context : ObjectContext, new()
    {
        private static ConcurrentDictionary<Type, ObjectContext> m_contexts = new ConcurrentDictionary<Type, ObjectContext>();
        //private static Dictionary<Type, ObjectContext> m_contexts = new Dictionary<Type, ObjectContext>();
        int m_pageSize;
        int m_pageNumber = 1;
        int m_skip = 0;
        int m_numberOfPages = 0;
        IPager m_pager = null;
        bool m_useFiltering = false;

        #region Properties...
        public bool UseFiltering
        {
            get { return m_useFiltering; }
            set { m_useFiltering = value; }
        }

        public IPager Pager
        {
            get { return m_pager; }
            set { m_pager = value; }
        }

        public int NumberOfPages
        {
            get { return m_numberOfPages; }
            set 
            { 
                m_numberOfPages = value;

                if (this.Pager != null)
                {
                    this.Pager.NumberOfPages = this.NumberOfPages;
                }
            }
        }

        public int Skip
        {
            get 
            {
                //if (m_skip < 0) m_skip = 1;

                return m_skip; 
            }
            set 
            {
                //if (value < 0) m_skip = 1;
                // else 
                    
                    m_skip = value; 
            }
        }

        public int PageSize
        {
            get { return m_pageSize; }
            set { m_pageSize = value; }
        }

        public int PageNumber
        {
            get { return m_pageNumber; }
            set { m_pageNumber = value; }
        }
        #endregion

        #region Constructor(s)...
        public PagedFacadeBase(int pageSize)
        {
            m_pageSize = pageSize;
        }
        #endregion

        #region public Methods...
        public Context GetContext()
        {
            Context m_c = null;

            if (m_contexts.ContainsKey(typeof(Context)))
            {
                m_c = (Context)m_contexts[typeof(Context)];
            }
            else
            {
                m_c = new Context();

                //m_contexts.Add(typeof(Context), m_c);
                m_contexts.AddOrUpdate(typeof(Context), m_c, (k, v) => v);
            }

            return m_c;
        }

        public void Previous()
        {
            if (m_pageNumber > 0)
            {
                m_pageNumber--;
            }
        }

        public void Next()
        {
            if (m_pageNumber < NumberOfPages)
            {
                m_pageNumber++;
            }
        }

        public void First()
        {
            m_pageNumber = 1;
        }

        public void Last()
        {
            m_pageNumber = NumberOfPages;
        }


        public void RunAsync<T>(Func<T> action, BackgroundWorkerCallbackBase.Callback callback)
        {
            BackGroundWorkerWrapper<T> p = new BackGroundWorkerWrapper<T>(action, callback);
            p.RunWorkerAsync();

            //m_pageNumber++;
            if (m_useFiltering)
            {
                m_skip = 0;
                m_useFiltering = false;
            }
            else m_skip = (m_pageNumber - 1) * m_pageSize;
        }

        public void RunAsync<T>(Func<T> action, BackgroundWorkerCallbackBase.Callback callback, params object[] argument)
        {
            BackGroundWorkerWrapper<T> p = new BackGroundWorkerWrapper<T>(action, callback);
            p.RunWorkerAsync(argument);

            //m_pageNumber++;
            if (m_useFiltering)
            {
                m_skip = 0;
                m_useFiltering = false;
            }
            else m_skip = (m_pageNumber - 1) * m_pageSize;
        }

        public void Transact(Action action)
        {
            using (TransactionScope transaction = new TransactionScope())
            {
                action();
                transaction.Complete();
            }
        }

        public void Transact(Action action, TransactionScopeOption scopeOption)
        {
            using (TransactionScope transaction = new TransactionScope(scopeOption))
            {
                action();
                transaction.Complete();
            }
        }
        #endregion

        protected internal int CalcNumberOfPages(int numberOfRecords)
        {
            int retValue = 1;

            if (numberOfRecords > 0) retValue = (numberOfRecords / PageSize) + 1;
            else retValue = 1;

            this.NumberOfPages = retValue;

            this.Pager.NumberOfRecords = numberOfRecords;

            return retValue;
        }
    }
}
